const path = require('path');
// var findNodeModules = require('find-node-modules');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); //优化和压缩CSS资源的插件
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); //webpack5优化和压缩CSS资源的插件
const TerserPlugin = require('terser-webpack-plugin'); //优化和压缩JS资源的插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const PurgecssPlugin = require("purgecss-webpack-plugin"); //去除未使用的 css，一般与 glob、glob-all 配合使用
const { glob } = require('glob'); //全局
var LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const smw = new SpeedMeasureWebpackPlugin(); //费时分析,但和MiniCssExtractPlugin不兼容
 
/* 
CDN
HTML放在自己的服务器上，不缓存，关闭服务器缓存，每次访问服务器都可以获取最新的资源
里面的静态文件js、css、image都指向CDN的地址，并且文件名带上hash值
为了可以并行加载，需要把不同类型的文件和不同的文件放在不同的CDN服务器上
为了避免同一时间对同一个域名请求数并发的限制，不同的资源放在不同的域名服务器进行并行加载
多个域名后会增加域名解析时间。可以通过在 HTML HEAD 标签中 加入<link rel="dns-prefetch" href="http://img.ikki.cn">去预解析域名，以降低域名解析带来的延迟 
*/


/* 
开启了sideEffects配置后，webpack在打包时就会先检查当前代码所属的package.json中有没有sideEffects的标识，
以此来判断这个模块是不是有副作用。如果这个模块没有副作用，这些没被用到的模块就不会被打包。（这个特性在production模式下会自动开启）
在package.json中配置以下"sideEffects":false.此时再去执行打包，bundle.js中就会清除未引用代码了。 
*/


module.exports = 
// smw.wrap(
    { //smw.wrap()费时分析
    // mode: 'development',
    mode: 'none',//优化和压缩CSS、JS资源将mode置为none

    // module: 每一个文件其实都可以看成一个 module
    // chunk: webpack打包最终生成的代码块，代码块会生成文件，一个文件对应一个chunk
    // 在webpack5之前，没有从entry打包的chunk文件(例如懒加载），都会以1、2、3...的文件命名方式输出,删除某些些文件可能会导致缓存失效
    // 在生产模式下，默认启用这些功能chunkIds: "deterministic", moduleIds: "deterministic"，此算法采用确定性的方式将短数字 ID(3 或 4 个字符)短hash值分配给 modules 和 chunks
    // 结论：开发可以使用named方便阅读和调试，生产使用deterministic
    /* optimization: {
        moduleIds: 'deterministic', //natural=>按使用顺序的数字ID named=>方便调试的高可读性id deterministic=>根据模块名称生成简短的hash值 size=>根据模块大小生成的数字id
        chunkIds: 'deterministic',


        webpack 现在能够跟踪对导出的嵌套属性的访问
        这可以改善重新导出命名空间对象时的Tree Shaking(清除未使用的导出和混淆导出)

        webpack 4 没有分析模块的导出和引用之间的依赖关系
        webpack 5 可以对模块中的标志进行分析，找出导出和引用之间的依赖关系

        webpack 曾经不进行对 CommonJS 导出和 require()调用时的导出使用分析
        webpack 5 增加了对一些 CommonJS 构造的支持，允许消除未使用的 CommonJs 导出，

        sideEffects: true, //副作用
        usedExports: true,  //表示在输出结果中模块只导出外部使用了的成员。
        minimize: true, //启用压缩JS
        minimizer: [new TerserPlugin(), new CssMinimizerPlugin()]
    }, */
    // webpack5缓存，缓存生成的webpack模块和chunk,来改善构建速度
    /* cache: {
        type: 'filesystem', //写入缓存到硬盘  filesystem=》文件系统
        cacheDirectory:path.resolve(__dirname,'node_modules/.cache/webpack') //缓存的基本目录
    }, */
    devtool: false,
    entry:{
        main:'./src/index.js',
        // vendor:['lodash']
    },
    // hash 是整个项目的hash值，其根据每次编译内容计算得到，每次编译之后都会生成新的hash,即修改任何文件都会导致所有文件的hash发生改变
    // chunkhash 每个入口都有自己的chunkhash 如果本入口对应的文件发生改变，chunkhash会改变，如果没有改变，chunkhash会保持不变
    // 使用chunkhash存在一个问题，就是当在一个JS文件中引入CSS文件，编译后它们的hash是相同的，而且只要js文件发生改变 ，关联的css文件hash也会改变,
    // 这个时候可以使用mini-css-extract-plugin里的contenthash值，保证即使css文件所处的模块里就算其他文件内容改变，只要css文件内容不变，那么不会重复构建
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name]-[chunkhash].js',
        
        // target:"web",

        library:'calculator',//指定导出库的名称 
        // libraryExport: 'minus',//配置导出的模块中哪些子模块需要被导出，它只有在libraryTarget设置为commonjs 或者 commonjs2 的时候才有用
        // libraryTarget:'var' //只能以script标签的形式引入我们的库	 
        // libraryTarget:'commonjs', //只能按照commonjs的规范引入我们的库（exports.calculator = require("./src/index.js");）
        // libraryTarget:'commonjs2', //以何种方式导出，如果是commonjs2那么library这个属性失去意义。(module.exports = require("./src/index.js");)
        // libraryTarget:'this|window|global', //编写的库将通过 this|window|global 被赋值给通过 library 指定的名称,(window["calculator"]= (function (modules) {}({}))
        libraryTarget:'umd' //可以用script、commonjs、amd引入  

    },

    //此处是在模块里找依赖的模块时有效(require import)
    resolve: {
        extensions: [".js",".jsx",".json",".css"],// 指定extension之后可以不用在require或是import的时候加文件扩展名,会依次尝试添加扩展名进行匹配
        alias:{ //配置别名可以加快webpack查找模块的速度
            bootstrap:path.resolve(__dirname,'node_modules/bootstrap/dist/css/bootstrap.css')
        },
        modules: ['node_modules'],//指定去哪个目录中查找对应的模块
        mainFields: ['browser', 'module', 'main'],//默认情况下package.json 文件则按照文件中 main 字段的文件名来查找文件
        // 配置output.target === "web" 或者 output.target === "webworker" 时 mainFields 默认值是：
        //mainFields: ['browser', 'module', 'main'],
        // output.target 的值为其他时，mainFields 默认值为：
        //mainFields: ["module", "main"],
        mainFiles: ["index", "main"], //当目录下没有 package.json 文件时，我们说会默认使用目录下的 index.js 这个文件，


        // webpack4带了许多Node.js核心模块的polyfill,一旦模块中使用了任何核心模块(如crypto)，这些模块就会被自动启用
        // webpack5不再自动引入这些polyfill
        fallback: {// 在crypto-js中不引入以下crypto，buffer，stream模块的polyfill
            crypto: false,
            buffer: false,
            stream: false
        }
    },
    // webpack会先根据resolveLoader里面的loader，没有的话再查找依赖中
    resolveLoader: { //仅用于解析webpack的loader包，选项与上面的resolve对象的属性集合相同
        /* alias:{
            'babel-loader':path.resolve('loaders/babel-loader.js'),
            'file-loader':path.resolve('loaders/file-loader.js'),
        }, */
        modules: ["loaders", "node_modules"],//在loaders，node_modules文件夹查找
        extensions: [ '.js', '.json' ], 
        mainFields: [ 'loader', 'main' ] 
    }, 
    module: {
        // 不去分析这些模块的依赖，因为他不可能有依赖，所以不去把它转成ast语法树，分析里的依赖模块
        // 注意点：使用 noParse 进行忽略的模块文件中不能使用 import、require、define 等导入机制
        noParse: /jquery|lodash/,
        /* 
        noParse: (moduleName) => {
             return /query|lodash/.test(moduleName);
        }, 
        */
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: [
                    {
                        //把这个 loader 放置在其他 loader 之前， 放置在这个 loader 之后的 loader 就会在一个单独的 worker 池(worker pool)中运行
                        loader: 'thread-loader', 
                        options: {
                            workers: 3
                        }
                    },
                    {
                        loader: 'babel-loader',
                        options: {
                            // cacheDirectory: true //babel编译 后把结果缓存起来，下次编译 的时候可以复用上次的结果
                        }
                    },
                    // 'loader1'
                ]
            },
            {
                test: /\.css$/,
                // include: path.resolve(__dirname, "src"),
                // exclude: /node_modules/,
                use: [MiniCssExtractPlugin.loader, "css-loader"],
            },
            {
                test: /\.(jpg|png|gif)$/,
                type: 'asset',//必定会输出一个文件
                parser: {
                    //如果asset后面没加其他的字段，那么会根据这个条件做选择，如果小于maxSize的话就变成base64字符串，如果大于的就拷贝文件并返回新的地址
                    dataUrlCondition: {
                        maxSize: 4 * 1024 // 4kb
                    }
                },
                generator: {
                    filename: 'images/[hash][ext]'
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            // 压缩html
            minify:{
                collapseWhitespace: true,
                removeComments: true
            }
        }),


        new MiniCssExtractPlugin({
            filename: 'style/[name]-[contenthash].css'
        }),


        // 每次打包先清除一个dist目录
        new CleanWebpackPlugin({
            cleanOnceBeforeBuildPatterns: ['**/*']
        }),


        // 可以去除未使用的 css，一般与 glob、glob-all 配合使用
        // 必须和mini-css-extract-plugin配合使用
        // new PurgecssPlugin({
        //     paths: glob.sync(`${path.resolve('src')}/**/* `, { nodir: true })
        // }),


        // IgnorePlugin用于忽略某些特定的模块，让webpack不把这些指定的模块打包进去
        // new webpack.IgnorePlugin({
        //     contextRegExp: /moment$/,//忽略 哪个模块
        //     resourceRegExp: /locale///忽略模块内的哪些资源
        // }),


        // new OptimizeCssAssetsWebpackPlugin({}), //压缩CSS

        // 需要配合webpack和webpack-cli一起使用。这个插件的功能是生成代码分析报告，帮助提升代码质量和网站性能
        // new BundleAnalyzerPlugin(),

        new webpack.optimize.ModuleConcatenationPlugin(),//作用域提升，只支持es6规范，不支持commonjs


    ]
}
// );

